﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Data;

namespace Core
{
    public abstract class Controller<T>
        where T : DBO<T>
    {
        #region Helpers
        /// <summary>
        /// Convert list<object> to list<T>
        /// </summary>
        /// <param name="items">The list object</param>
        /// <returns>List T</returns>
        private static List<T> Convert(List<object> items)
        {
            if (items == null)
                return null;

            return items.ConvertAll<T>(delegate(object item)
            {
                return (T)item;
            });
        }

        /// <summary>
        /// Get the first item in list
        /// </summary>
        /// <param name="items">The list object</param>
        /// <returns>The fisrt item</returns>
        /// <remarks>Return null if the list is null or empty.</remarks>
        private static T FirstItem(List<object> items)
        {
            if (items == null || items.Count == 0)
                return default(T);

            return (T)items[0];
        }
        #endregion

        #region Insert-Update-Delete
        /// <summary>
        /// This method call insert method from DataAccessLayer using the provided parameter.
        /// </summary>
        /// <returns>Return ID if add successful; otherwise return -1.</returns>    
        public static int Insert(T item)
        {
            Exception ex = null;
            int result = DataAccessLayer.Insert(item, ref ex);

            if (ex != null)
                throw ex;

            return result;
        }

        /// <summary>
        /// This method call insert method from DataAccessLayer using the provided parameter.
        /// </summary>
        /// <param name="item">
        /// The item to insert
        /// </param>
        /// <param name="ex">
        /// Keep exception in ex if has any exception during execute command
        /// </param>
        /// <returns>Return ID if add successful; otherwise return -1.</returns>    
        public static int Insert(T item, ref Exception ex)
        {
            int result = DataAccessLayer.Insert(item, ref ex);
            return result;
        }

        /// <summary>
        /// This method call update method in DataAccessLayer 
        /// using this to pass values.
        /// </summary>
        /// <returns>Status (true: successful,  false: unsuccessful ) </returns>        
        public static bool Update(T item)
        {
            Exception ex = null;
            bool result = DataAccessLayer.Update(item, ref ex);

            if (ex != null)
                throw ex;

            return result;
        }

        /// <summary>
        /// This method call update method in DataAccessLayer 
        /// using this to pass values.
        /// </summary>
        /// <param name="item">
        /// The item to update
        /// </param>
        /// <param name="ex">
        /// Keep exception in ex if has any exception during execute command
        /// </param>
        /// <returns>Status (true: successful,  false: unsuccessful ) </returns>        
        public static bool Update(T item, ref Exception ex)
        {
            bool result = DataAccessLayer.Update(item, ref ex);
            return result;
        }

        /// <summary>
        /// This method call delete method in DataAccessLayer using this to pass values.
        /// </summary>
        /// <returns>Status (true: successful,  false: unsuccessful ) </returns>             
        public static bool Delete(T item)
        {
            Exception ex = null;
            bool result = DataAccessLayer.Delete(item, ref ex);

            if (ex != null)
                throw ex;

            return result;
        }

        /// <summary>
        /// This method call delete method in DataAccessLayer using this to pass values.
        /// </summary>
        /// <param name="item">
        /// The item to delete
        /// </param>
        /// <param name="ex">
        /// Keep exception in ex if has any exception during execute command
        /// </param>
        /// <returns>Status (true: successful,  false: unsuccessful ) </returns>             
        public static bool Delete(T item, ref Exception ex)
        {
            bool result = DataAccessLayer.Delete(item, ref ex);
            return result;
        }
        #endregion

        #region Select all items, Select some items with pagging

        /// <summary>
        /// Get all items
        /// </summary>
        /// <returns>The list of T</returns>
        public static List<T> SelectItems()
        {
            object condition = Activator.CreateInstance(typeof(T));

            Exception ex = null;
            List<object> items = DataAccessLayer.GetListObject(condition, ref ex);

            if (ex != null)
                throw ex;

            return Convert(items);
        }

        public static List<T> SelectItems(ref Exception ex)
        {
            object condition = Activator.CreateInstance(typeof(T));

            List<object> items = DataAccessLayer.GetListObject(condition, ref ex);

            return Convert(items);
        }

        /// <summary>
        /// Select some items with pagging
        /// </summary>
        /// <param name="page">The page need get Ts</param>
        /// <param name="pageSize">The size of page.</param>
        /// <returns></returns>
        public static List<T> SelectItems(int page, int pageSize, ref int total)
        {
            object condition = Activator.CreateInstance(typeof(T));

            Exception ex = null;
            List<object> items = DataAccessLayer.GetListObject(condition, page, pageSize, ref total, ref ex);

            if (ex != null)
                throw ex;

            return Convert(items);
        }

        public static List<T> SelectItems(int page, int pageSize, ref int total, ref Exception ex)
        {
            object condition = Activator.CreateInstance(typeof(T));

            List<object> items = DataAccessLayer.GetListObject(condition, page, pageSize, ref total, ref ex);

            return Convert(items);
        }
        #endregion

        #region Find a item, Find all items, Find some items with pagging

        /// <summary>
        /// Find all items match condition contain in obj.
        /// </summary>
        /// <param name="condition">The obj contain conditions to filter.</param>
        /// <returns>The list obj match conditions.</returns>
        public static T FindItem(T condition)
        {
            Exception ex = null;
            List<object> items = DataAccessLayer.FindListObjects(condition, ref ex);

            if (ex != null)
                throw ex;

            return FirstItem(items);
        }

        public static T FindItem(T condition, ref Exception ex)
        {
            List<object> items = DataAccessLayer.FindListObjects(condition, ref ex);

            return FirstItem(items);
        }

        /// <summary>
        /// Find all items match condition contain in obj.
        /// </summary>
        /// <param name="condition">The obj contain conditions to filter.</param>
        /// <returns>The list obj match conditions.</returns>
        public static List<T> FindItems(T condition)
        {
            Exception ex = null;
            List<object> items = DataAccessLayer.FindListObjects(condition, ref ex);

            if (ex != null)
                throw ex;

            return Convert(items);
        }

        public static List<T> FindItems(T condition, ref Exception ex)
        {
            List<object> items = DataAccessLayer.FindListObjects(condition, ref ex);

            return Convert(items);
        }

        /// <summary>
        /// Find all items match condition contain in obj.
        /// </summary>
        /// <param name="condition">The obj contain conditions to filter.</param>
        /// <param name="page">The page need get Ts</param>
        /// <param name="pageSize">The size of page.</param>
        /// <returns></returns>
        public static List<T> FindItems(T condition, int page, int pageSize, ref int total)
        {
            Exception ex = null;
            List<object> items = DataAccessLayer.FindListObjects(condition, page, pageSize, ref total, ref ex);

            if (ex != null)
                throw ex;

            return Convert(items);
        }

        public static List<T> FindItems(T condition, int page, int pageSize, ref int total, ref Exception ex)
        {
            List<object> items = DataAccessLayer.FindListObjects(condition, page, pageSize, ref total, ref ex);

            return Convert(items);
        }

        #endregion

        #region Custom execute
        /// <summary>
        /// Execute a sqlcommand
        /// </summary>
        /// <param name="commandText">The sql command, maybe SqlStatement or Stored procedure name.</param>
        /// <param name="commandType">The type of sql sql command: text or storedprocedure</param>
        /// <param name="sqlParam">The sql params for sql command</param>
        /// <param name="outException">The out exception if has during execute the sqlcommand.</param>
        /// <returns></returns>
        public static DataTable ExecuteDataTable(string commandText, CommandType commandType, SqlParameter[] sqlParam, ref Exception outException)
        {
            Exception ex = null;

            DataTable result = DataAccessLayer.ExecuteDataTable(commandText, commandType, sqlParam, ref outException);

            if (ex != null)
                throw ex;

            return result;
        }

        public static DataTable ExecuteDataTable(string commandText, CommandType commandType, SqlParameter[] sqlParam, ref int total, ref Exception exception)
        {
            SqlService sqlService = new SqlService();
            sqlService.ClearParameters();
            foreach (SqlParameter param in sqlParam)
            {
                sqlService.AddParameter(param.ParameterName, param.Value);
            }
            sqlService.AddParameter("RowCount", 0, ParameterDirection.ReturnValue);

            DataTable dt = sqlService.GetDataTable(commandText, commandType, true, true, ref exception);

            total = (int)sqlService.GetParammeterValue("RowCount");


            return dt;
        }
        #endregion
    }
}


